package com.wanshu.sys.filter;

import com.alibaba.fastjson.JSON;
import com.wanshu.common.constant.SystemConstant;
import com.wanshu.common.result.JWTUtils;
import com.wanshu.sys.entity.SysUser;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录过滤器，登录成功生成JWT令牌并返回给前端
 *
 * @author 张颖辉（zyh）
 * @version 1.0.0
 * @date 2023/06/10
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    public TokenLoginFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }


    /**
     * 登录认证
     * 尝试验证:具体认证的方法
     *
     * @param request  请求
     * @param response 响应
     * @return {@link Authentication }
     * @throws AuthenticationException 身份验证异常
     * @author 张颖辉（zyh）
     * @date 2023/06/10
     * @version 1.0.0
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        //前后端分离 前端的用户名密码并不是表单提交的方式，而是JSON格式提交
        try {
            String loginInfo = getRequestJson(request);
            SysUser sysUser = JSON.parseObject(loginInfo, SysUser.class);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword());
            // 返回 登录认证结果
            return authenticationManager.authenticate(authenticationToken);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get请求json
     *
     * @param request 请求
     * @return {@link String }
     * @throws IOException ioexception
     * @author 张颖辉（zyh）
     * @date 2023/06/13
     * @version 1.0.0
     */
    private String getRequestJson(HttpServletRequest request) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        StringBuffer sb = new StringBuffer();
        String inputStr = null;
        while ((inputStr = bufferedReader.readLine()) != null) {
            sb.append(inputStr);
        }
        return sb.toString();
    }

    /**
     * 身份验证成功
     * 登录成功后的处理，返回给前端什么数据
     *
     * @param request    请求
     * @param response   响应
     * @param chain      链
     * @param authResult 身份验证结果
     * @throws IOException      ioexception
     * @throws ServletException servlet异常
     * @author 张颖辉（zyh）
     * @date 2023/06/10
     * @version 1.0.0
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        // 生成Token信息
        Map<String,String> map = new HashMap<>();
        map.put("username",authResult.getName());
        // TODO 还可以存储当前用户具有的角色
        // 生成对应的Token信息
        String token = JWTUtils.getToken(map);
        // 需要把生成的Token信息响应给客户端
        response.addHeader("Authorization", SystemConstant.SYS_TOKEN_PREFIX +token);
        //【header访问控制暴露】 允许在响应数据中暴露Authorization，否则只能在浏览器的网络中看到，而axios响应中的headers内没有Authorization
        response.addHeader("Access-Control-Expose-Headers","Authorization");
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("code", HttpServletResponse.SC_OK);
        resultMap.put("msg","认证通过");
        writer.write(JSON.toJSONString(resultMap));
        writer.flush();
        writer.close();
    }

    /**
     * 身份验证不成功
     * 登录失败后的处理，返回给前端什么数据
     *
     * @param request  请求
     * @param response 响应
     * @param failed   失败
     * @throws IOException      ioexception
     * @throws ServletException servlet异常
     * @author 张颖辉（zyh）
     * @date 2023/06/10
     * @version 1.0.0
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED);
        resultMap.put("msg","用户名或密码错误!");
        writer.write(JSON.toJSONString(resultMap));
        writer.flush();
        writer.close();
    }
}
